package com.cnap.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.cnap.db.entity.ApplicationPO;
import com.cnap.db.entity.ClusterInfoPO;
import com.cnap.db.entity.DeployClusterPO;
import com.cnap.db.entity.MicroServicePO;
import com.cnap.db.entity.ScaleStrategyPO;
import com.cnap.db.entity.ScheduleStrategyPO;
import com.cnap.db.entity.StrategyPO;
import com.cnap.db.mapper.MicroServiceMapper;
import com.cnap.db.mapper.ScaleStrategyMapper;
import com.cnap.db.mapper.ScheduleStrategyMapper;
import com.cnap.db.mapper.StrategyMapper;
import com.cnap.model.application.ApplicationLabel;
import com.cnap.model.application.ApplicationStatusEnum;
import com.cnap.model.cloud.CloudVendorsEnum;
import com.cnap.model.cloud.CommentResultForCloud;
import com.cnap.model.cloud.DeleteParam;
import com.cnap.model.cloud.scaling.CreateScalingDTO;
import com.cnap.model.cloud.scaling.ScalingPolicyDTO;
import com.cnap.model.cloud.scaling.UpdateScalingParam;
import com.cnap.model.common.ResultCode;
import com.cnap.model.exception.JsonException;
import com.cnap.model.schedule.DistributeParam;
import com.cnap.model.schedule.OperateParam;
import com.cnap.model.schedule.OperateTypeEnum;
import com.cnap.model.schedule.StrategyDTO;
import com.cnap.model.schedule.StrategyStatusEnum;
import com.cnap.model.schedule.StrategyTypeEnum;
import com.cnap.model.schedule.engine.CommentResultForEngine;
import com.cnap.model.schedule.engine.DeployPolicyDistributeReqV2;
import com.cnap.model.schedule.engine.EngineClusterInfo;
import com.cnap.model.schedule.engine.OperateReq;
import com.cnap.model.schedule.engine.ValidateResponse;
import com.cnap.model.schedule.engine.ValidateResult;
import com.cnap.model.schedule.engine.alg.AlgDeployClusterInfo;
import com.cnap.model.schedule.engine.alg.ResourceTypeEnum;
import com.cnap.model.stage.SingleStageDeployParam;
import com.cnap.model.stage.SingleStageVO;
import com.cnap.model.stage.StageDeployParam;
import com.cnap.model.stage.StageDetailTypeEnum;
import com.cnap.model.stage.StageTypeEnum;
import com.cnap.model.stage.StageVO;
import com.cnap.model.strategy.DistributeParamV2;
import com.cnap.model.strategy.OperateParamV2;
import com.cnap.service.*;
import com.cnap.utils.JsonUtil;
import com.cnap.utils.TokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

/**
 * <类文件描述>
 *
 * @author xc
 **/
@Service
public class OperateServiceImpl implements OperateService {
    private static final Logger LOGGER = LoggerFactory.getLogger(OperateServiceImpl.class);

    public static final Map<String, ScheduledFuture<?>> ASYNC_DELETE_MAP = new ConcurrentHashMap<>();

    private final MicroServiceMapper microServiceMapper;
    private final StrategyMapper strategyMapper;
    private final ClusterInfoService clusterInfoService;
    private final AlgorithmEngineService algorithmEngineService;
    private final CloudMgmtService cloudMgmtService;
    private final DistributeDeployService distributeDeployService;
    private final ScheduleStrategyMapper scheduleStrategyMapper;
    private final ScaleStrategyMapper scaleStrategyMapper;
    private final ApplicationService applicationService;
    private final IntelligentScheduleService intelligentScheduleService;
    private final ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Autowired
    public OperateServiceImpl(MicroServiceMapper microServiceMapper, StrategyMapper strategyMapper,
                              ClusterInfoService clusterInfoService, AlgorithmEngineService algorithmEngineService,
                              CloudMgmtService cloudMgmtService, DistributeDeployService distributeDeployService,
                              ScheduleStrategyMapper scheduleStrategyMapper, ScaleStrategyMapper scaleStrategyMapper,
                              ApplicationService applicationService, IntelligentScheduleService intelligentScheduleService,
                              ThreadPoolTaskScheduler threadPoolTaskScheduler) {
        this.microServiceMapper = microServiceMapper;
        this.strategyMapper = strategyMapper;
        this.clusterInfoService = clusterInfoService;
        this.algorithmEngineService = algorithmEngineService;
        this.cloudMgmtService = cloudMgmtService;
        this.distributeDeployService = distributeDeployService;
        this.scheduleStrategyMapper = scheduleStrategyMapper;
        this.scaleStrategyMapper = scaleStrategyMapper;
        this.applicationService = applicationService;
        this.intelligentScheduleService = intelligentScheduleService;
        this.threadPoolTaskScheduler = threadPoolTaskScheduler;
    }

    @Override
    public boolean distributeV2(DistributeParamV2 distributeParam) {
        String svcId = distributeParam.getServiceId();
        MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(svcId);
        if (Objects.isNull(microServicePO)) {
            LOGGER.error("can't find micro service, id={}", svcId);
            throw new JsonException(500, "未找到该微服务");
        }
        ScheduleStrategyPO scheduleStrategyPO = scheduleStrategyMapper.selectByServiceId(svcId);
        List<ScaleStrategyPO> scaleStrategyPOS = scaleStrategyMapper.selectByServiceId(svcId);
        if (Objects.isNull(scheduleStrategyPO)) {
            LOGGER.error("micro service id={} has no strategy", svcId);
            throw new JsonException(500, "请配置策略");
        }

        // 组装请求
        DeployPolicyDistributeReqV2 reqV2 = getDeployPolicyDistributeReqV2(microServicePO);
        reqV2.setDeployPolicyConfigs(scheduleStrategyPO.toDeployPolicyConfigV2s());

        if (Objects.nonNull(scaleStrategyPOS)) {
            // 过滤虚机扩缩容策略
            // 过滤none参数的策略
            scaleStrategyPOS =
                    scaleStrategyPOS.stream().filter(po -> !"虚机扩缩容策略".equals(po.getStrategyName())).filter(po -> !(
                            "{\"policy\":\"none\"}").equals(po.getStrategyParam())).collect(Collectors.toList());
            reqV2.setScalePolicyConfigs(scaleStrategyPOS.stream().map(ScaleStrategyPO::getStrategyParam).collect(Collectors.toList()));
        } else {
            LOGGER.warn("service id={} has no scale strategy", svcId);
            reqV2.setScalePolicyConfigs(Collections.emptyList());
        }

        List<String> clusterNames = distributeParam.getClusters().stream().map(DeployClusterPO::getClusterName).collect(Collectors.toList());
        reqV2.setClusters(clusterNames);

        CommentResultForEngine<ValidateResponse> result = algorithmEngineService.distributeV2(reqV2);
        List<ValidateResult> validateResults = result.getData().getResults();
        for (ValidateResult validateResult : validateResults) {
            if (!validateResult.isPass()) {
                throw new JsonException(500, validateResult.getDetailMessage());
            }
        }
        // 部署成功后，需要更新部署信息，由于是异步的，此时不知道服务是否部署成功
        for (DeployClusterPO po : distributeParam.getClusters()) {
            clusterInfoService.saveDeployCluster(po);
        }
        // 开始智能决策周期性任务执行
        intelligentScheduleService.addNewIntelligentSchedule(svcId, scheduleStrategyPO.getIntelligentDuration(), scheduleStrategyPO.getIntelligentScheduleActive());

        return true;
    }

    @Override
    public boolean operateV2(OperateParamV2 operateParam) {
        MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(operateParam.getSvcId());
        if (Objects.isNull(microServicePO)) {
            LOGGER.error("can't find micro service for id={}", operateParam.getSvcId());
            throw new JsonException(500, "未找到该微服务信息");
        }
        // 判断权限
        if (!microServicePO.getUserName().equals(TokenUtils.getUserName())) {
            LOGGER.error("user {} has no permissions to operate microservice {}", TokenUtils.getUserName(),
                    operateParam.getSvcId());
            throw new JsonException(ResultCode.FORBIDDEN);
        }
        OperateTypeEnum operateTypeEnum = OperateTypeEnum.getOperateTypeFromType(operateParam.getOperationType());
        // 修改状态前置，防止算法引擎返回状态太快
        microServiceMapper.updateMicroServiceStatus(operateParam.getSvcId(), operateTypeEnum.getStatusValue());

        String svcId = operateParam.getSvcId();

        StageVO stageVO = distributeDeployService.getStageInfoByServiceId(operateParam.getSvcId());

        if (OperateTypeEnum.SUSPEND.equals(operateTypeEnum)) {
            // 暂停
            // 直接向算法引擎发送暂停请求（删除svc）
            OperateReq req = new OperateReq();
            req.setSvcId(operateParam.getSvcId());
            req.setOperation(operateParam.getOperationType());
            algorithmEngineService.operate(req);
        } else if (OperateTypeEnum.RESUME.equals(operateTypeEnum)) {
            // 恢复
            // 直接发送请求到算法引擎（恢复删除的svc）
            DistributeParamV2 distributeParam = new DistributeParamV2();
            distributeParam.setServiceId(svcId);

            List<DeployClusterPO> deployClusterPOS = clusterInfoService.getDeployClusterBySvcId(svcId);
            distributeParam.setClusters(deployClusterPOS);
            // 删除此时的4-1 4-2
            // 删除操作提前，防止算法引擎提前返回
            distributeDeployService.deleteStagesBySvcIdAndType(svcId, StageTypeEnum.DISTRIBUTE.getType());
            LOGGER.info("delete distribute stages, svcId={}", svcId);

            distributeV2(distributeParam);

        } else if (OperateTypeEnum.DELETE.equals(operateTypeEnum)) {
            // 删除流程
            delete(operateParam, microServicePO, svcId, stageVO);
        } else if (OperateTypeEnum.RE_DISTRIBUTE.equals(operateTypeEnum)) {
            // 重新部署
            // 通知集群控制台
            LOGGER.info("try to send request to multi system to delete vm info by reDistribute, svcId={}", svcId);
            DeleteParam deleteParam = getDeleteParam(operateParam.getSvcId(), stageVO);
            CommentResultForCloud res = cloudMgmtService.deleteVmAndOtherInfo(deleteParam);
            if (res.getCode() != 200) {
                LOGGER.warn("can't delete other from multi system, svcId={}, current stage={}", svcId, deleteParam.getType());
            }

            // 需要通知算法引擎先删除
            // 此处通知算法引擎删除，由于是异步的，会发送更新微服务状态接口，导致下面会删除改微服务的所有信息
            // 所以新增一个操作类型 delete_no_response，告诉算法引擎不需要更新改微服务状态了
            OperateReq req = new OperateReq();
            req.setSvcId(svcId);
            req.setOperation(OperateTypeEnum.DELETE_NO_RESPONSE.getType());
            algorithmEngineService.operate(req);
            // 改变了，需要重新部署
            // 先删除所有的阶段信息
            distributeDeployService.deleteStagesByServiceId(svcId);
            LOGGER.info("delete stages by reDistribute, svcId={}", svcId);
            // 删除原有部署信息
            clusterInfoService.deleteDeployClusterBySvcId(svcId);
            LOGGER.info("delete deploy cluster by reDistribute, svcId={}", svcId);

            distributeDeployService.startDistributeDeploy(Collections.singletonList(svcId));
        }
        return true;
    }

    private DeployPolicyDistributeReqV2 getDeployPolicyDistributeReqV2(MicroServicePO microServicePO) {
        DeployPolicyDistributeReqV2 reqV2 = new DeployPolicyDistributeReqV2();
        reqV2.setSvcId(microServicePO.getId());
        reqV2.setYaml(microServicePO.getYaml());
        reqV2.setPath(microServicePO.getPath());
        reqV2.setAppCategory(microServicePO.getCategory());
        reqV2.setFramework(microServicePO.getFramework());
        reqV2.setUserName(microServicePO.getUserName());
        // 需要获取应用的信息
        ApplicationPO applicationPO = applicationService.selectByAppId(microServicePO.getApplicationId());
        ApplicationLabel labels = applicationPO.getLabel();
        reqV2.setSceneTags(labels.getObjectScene());
        reqV2.setTechnologyTags(labels.getTechnology());
        return reqV2;
    }

    @Override
    // 废弃
    public boolean operate(OperateParam operateParam) {
        MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(operateParam.getSvcId());
        if (Objects.isNull(microServicePO)) {
            LOGGER.error("can't find micro service for id={}", operateParam.getSvcId());
            throw new JsonException(500, "未找到该微服务信息");
        }
        // 判断权限
        if (!microServicePO.getUserName().equals(TokenUtils.getUserName())) {
            LOGGER.error("user {} has no permissions to operate microservice {}", TokenUtils.getUserName(),
                    operateParam.getSvcId());
            throw new JsonException(ResultCode.FORBIDDEN);
        }
        OperateTypeEnum operateTypeEnum = OperateTypeEnum.getOperateTypeFromType(operateParam.getOperationType());
        // 修改状态前置，防止算法引擎返回状态太快
        microServiceMapper.updateMicroServiceStatus(operateParam.getSvcId(), operateTypeEnum.getStatusValue());

        String type = operateParam.getOperationType();
        String svcId = operateParam.getSvcId();

        StageVO stageVO = distributeDeployService.getStageInfoByServiceId(operateParam.getSvcId());

        if (OperateTypeEnum.SUSPEND.getType().equals(type)) {
            // 暂停流程
            // 1. 更新调度策略集群信息
            // 2. 向算法引擎发送暂停请求
            updateScheduleStrategy(operateParam.getSvcId());
            LOGGER.info("update cluster info by suspend, svcId={}", operateParam.getSvcId());
            LOGGER.info("send request to alg engine by suspend, svcId={}", operateParam.getSvcId());
            OperateReq req = new OperateReq();
            req.setSvcId(operateParam.getSvcId());
            req.setOperation(operateParam.getOperationType());
            algorithmEngineService.operate(req);
        } else if (OperateTypeEnum.RESUME.getType().equals(type)) {
            // 恢复流程
            // 1. 判断是否需要发送到集群控制台
            // 1.1 发送到集群控制台
            // 1.1.1 先发送删除信息到算法引擎，删除旧集群上的微服务
            // 1.1.2 再发送请求到集群控制台
            // 1.2 直接恢复，发送请求到算法引擎
            resume(svcId, microServicePO);
            // 更新此时本地其他微服务部署集群的虚机扩缩容策略
            StrategyPO vmStrategy = strategyMapper.selectVmScaleByServiceId(svcId);
            updateOtherServiceLocalVmStrategy(vmStrategy);
        } else if (OperateTypeEnum.DELETE.getType().equals(type)) {
            // 删除流程
            delete(operateParam, microServicePO, svcId, stageVO);
        }
        return true;
    }

    private void delete(OperateParamV2 operateParamV2, MicroServicePO microServicePO, String svcId, StageVO stageVO) {
        OperateParam operateParam = new OperateParam();
        operateParam.setOperationType(operateParamV2.getOperationType());
        operateParam.setSvcId(operateParamV2.getSvcId());
        delete(operateParam, microServicePO, svcId, stageVO);
    }

    private void delete(OperateParam operateParam, MicroServicePO microServicePO, String svcId, StageVO stageVO) {
        // 启动定时任务，超时20分钟，则更改微服务状态
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        LocalDateTime startUpdateTime = now.plusMinutes(20);
        Date migrateDate = Date.from(startUpdateTime.atZone(ZoneId.of("Asia/Shanghai")).toInstant());
        ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(() -> {
            MicroServicePO po = microServiceMapper.selectMicroServiceById(svcId);
            if (Objects.nonNull(po) && StrategyStatusEnum.DELETING.getStatus() == po.getStatus()) {
                LOGGER.warn("[delete-svc]: svc={} has been deleted more than 20 minutes, update to delete fail", svcId);
                microServiceMapper.updateMicroServiceStatus(svcId, StrategyStatusEnum.DELETE_FAILED.getStatus());
            }
        }, migrateDate);
        ScheduledFuture<?> oldFuture = ASYNC_DELETE_MAP.remove(svcId);
        if (Objects.nonNull(oldFuture)) {
            oldFuture.cancel(true);
            LOGGER.error("[delete-svc]: stop old async thread, svcId={}", svcId);
        }
        ASYNC_DELETE_MAP.put(svcId, future);
        LOGGER.info("[delete-svc]: start async thread for svc={}, time out={}", svcId, startUpdateTime);
        // 发送删除请求到集群控制台
        LOGGER.info("try to send request to multi system to delete vm info, svcId={}", svcId);
        DeleteParam deleteParam = getDeleteParam(operateParam.getSvcId(), stageVO);
        CommentResultForCloud res = cloudMgmtService.deleteVmAndOtherInfo(deleteParam);
        if (res.getCode() != 200) {
            LOGGER.warn("can't delete other from multi system, svcId={}, current stage={}", svcId, deleteParam.getType());
        }

        // 1. 根据是否有阶段4判断是否要发送到算法引擎
        // 1.1 发送到算法引擎，后续删除是走更新微服务状态接口，包括策略和阶段信息
        boolean sendDeleteToAlgEngine = false;
        if (Objects.nonNull(stageVO.getFourthStages()) && !stageVO.getFourthStages().isEmpty()) {
            // 说明到阶段4了，需要通知算法引擎
            // 需要再判断是否再部署验证时出错了
            boolean errorFlag = false;
            for (SingleStageVO stage : stageVO.getFourthStages()) {
                if (CharSequenceUtil.isNotEmpty(stage.getErrorMsg())) {
                    errorFlag = true;
                    break;
                }
            }
            if (!errorFlag) {
                // 正常情况下到步骤4，通知算法引擎删除
                OperateReq req = new OperateReq();
                req.setSvcId(operateParam.getSvcId());
                req.setOperation(operateParam.getOperationType());
                algorithmEngineService.operate(req);
                sendDeleteToAlgEngine = true;
            }
        }

        if (!sendDeleteToAlgEngine) {
            // 如果没有发送到算法引擎，则自己删除本地信息
            // 删除集群信息
            clusterInfoService.deleteClusterInfoBySvcId(svcId);
            // 删除策略

            scheduleStrategyMapper.deleteByServiceId(svcId);
            scaleStrategyMapper.deleteByServiceId(svcId);

            // 微服务更新为初始状态
            microServiceMapper.updateMicroServiceStatus(svcId, StrategyStatusEnum.INIT.getStatus());
            // 更新应用状态
            ApplicationService applicationService = SpringUtil.getBean(ApplicationService.class);
            applicationService.updateApplicationStatus(microServicePO.getApplicationId(), ApplicationStatusEnum.SPLIT.getValue());
            // 删除该微服务阶段信息
            distributeDeployService.deleteStagesByServiceId(svcId);
        }
    }

    private void updateExtraInfo(String svcId, ClusterInfoPO clusterInfoPO) {
        // 更新extra_info中的集群信息，不管集群有没有变化，并且把虚机信息删除掉
        // 集合里固定为3个
        AlgDeployClusterInfo algRecommend = clusterInfoPO.getAlgDeployClusterInfos().stream()
                .filter(cluster -> clusterInfoPO.getRecommendCloud().equals(cluster.getProviderName()))
                .collect(Collectors.toList()).get(0);

        Map<String, String> newExtraInfo = new HashMap<>();
        newExtraInfo.put("ip", algRecommend.getIp());
        newExtraInfo.put("innerIp", algRecommend.getInnerIp());
        newExtraInfo.put("name", algRecommend.getName());
        newExtraInfo.put("providerName", algRecommend.getProviderName());
        if (CharSequenceUtil.isEmpty(algRecommend.getName())) {
            LOGGER.error("alg recommend cluster({}) is null, {}", clusterInfoPO.getRecommendCloud(), JsonUtil
                    .objectToJsonStr(algRecommend));
        } else {
            distributeDeployService.updateExtraInfo(svcId, StageDetailTypeEnum.ONE_TWO, null);
            distributeDeployService.updateExtraInfo(svcId, StageDetailTypeEnum.THREE_SEVEN,
                    Collections.singletonList(newExtraInfo));
        }
    }

    /**
     * 本地其他微服务如果部署在同一个集群上，更新其虚机扩缩容策略
     *
     * @param scaleStrategy 虚机扩缩容策略
     */
    private void updateOtherServiceLocalVmStrategy(StrategyPO scaleStrategy) {
        MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(scaleStrategy.getServiceId());
        ClusterInfoPO clusterInfoPO = clusterInfoService.getClusterInfoBySvcId(scaleStrategy.getServiceId());
        if (Objects.isNull(clusterInfoPO)) {
            LOGGER.error("current service has no cluster info, svcId={}", scaleStrategy.getServiceId());
            return;
        }
        List<EngineClusterInfo> engineClusterInfos = clusterInfoPO.getClusterInfos().stream()
                .filter(info -> clusterInfoPO.getUserChooseCloud().equals(info.getProviderName()))
                .filter(info -> Objects.nonNull(info.getName())).collect(Collectors.toList());
        if (engineClusterInfos.isEmpty()) {
            LOGGER.warn("current service has no exit cluster, svcId={}", scaleStrategy.getServiceId());
            return;
        }
        UpdateScalingParam updateScalingParam = new UpdateScalingParam();
        updateScalingParam.setProvider(clusterInfoPO.getUserChooseCloud());
        updateScalingParam.setClusterName(engineClusterInfos.get(0).getName());
        ScalingPolicyDTO scalingPolicyDTO = JsonUtil.jsonStrToObject(scaleStrategy.getStrategyParam(),
                ScalingPolicyDTO.class);
        if (Objects.isNull(scalingPolicyDTO)) {
            updateScalingParam.setScalingPolicyPOS(null);
        } else {
            updateScalingParam.setScalingPolicyPOS(scalingPolicyDTO.getParam());
        }
        updateScalingParam.setCategory(microServicePO.getCategory());
        MicroSvcService microSvcService = SpringUtil.getBean(MicroSvcService.class);
        microSvcService.updateScalingPolicy(updateScalingParam);
    }

    private void resume(String svcId, MicroServicePO microServicePO) {
        StrategyPO scheduleStrategy = strategyMapper.selectStrategyByServiceIdAndType(svcId, StrategyTypeEnum.SCHEDULE_STRATEGY.getValue());
        // 旧的部署信息
        List<EngineClusterInfo> oldEngineInfo = scheduleStrategy.getOldClusterInfos();
        EngineClusterInfo realEngineInfo =
                oldEngineInfo.stream().filter(EngineClusterInfo::isActive).collect(Collectors.toList()).get(0);
        boolean checkResult = checkIfSendRequestToAlgEngine(svcId, realEngineInfo);

        if (checkResult) {
            LOGGER.info("need send request to alg engine, svcId={}", svcId);
            // 可以从策略处获取集群信息
            // 也可以直接通过clusterInfoService获取
            // update：2023.02.06，strategy处的clusterInfos字段已废弃，应从clusterInfoService处获取，且此处通知算法引擎恢复微服务，应该不需要集群信息，那边已存储
            ClusterInfoPO clusterInfoPO = clusterInfoService.getClusterInfoBySvcId(svcId);

            updatePolicy(svcId, microServicePO, clusterInfoPO);

            // 未改变，通知算法引擎重新部署
            DistributeParam distributeParam = new DistributeParam();
            distributeParam.setServiceId(svcId);
            distributeParam.setYaml(microServicePO.getYaml());

            List<String> clusterNames =
                    scheduleStrategy.getClusterInfos().stream()
                            .filter(cluster -> clusterInfoPO.getUserChooseCloud().equals(cluster.getProviderName()))
                            .map(EngineClusterInfo::getName)
                            .collect(Collectors.toList());
            distributeParam.setClusters(clusterNames);

            // 删除此时的4-1 4-2
            // 删除操作提前，防止算法引擎提前返回
            distributeDeployService.deleteStagesBySvcIdAndType(svcId, StageTypeEnum.DISTRIBUTE.getType());
            LOGGER.info("delete distribute stages, svcId={}", svcId);

            MicroSvcService microSvcService = SpringUtil.getBean(MicroSvcService.class);
            microSvcService.distribute(distributeParam);

            updateExtraInfo(svcId, clusterInfoPO);
        } else {
            // 需要通知算法引擎先删除
            // 此处通知算法引擎删除，由于是异步的，会发送更新微服务状态接口，导致下面会删除改微服务的所有信息
            // 所以新增一个操作类型 delete_no_response，告诉算法引擎不需要更新改微服务状态了
            OperateReq req = new OperateReq();
            req.setSvcId(svcId);
            req.setOperation(OperateTypeEnum.DELETE_NO_RESPONSE.getType());
            algorithmEngineService.operate(req);
            // 改变了，需要重新部署
            // 先删除所有的阶段信息
            distributeDeployService.deleteStagesByServiceId(svcId);
            LOGGER.info("delete stages by resume microservice with distribute system, svcId={}", svcId);

            SingleStageDeployParam param = new SingleStageDeployParam();
            param.setSvcId(svcId);
            StageDeployParam stageDeployParam = new StageDeployParam();
            stageDeployParam.setParams(Collections.singletonList(param));
            distributeDeployService.startDistributeDeploy(stageDeployParam);
        }

    }


    private void updatePolicy(String svcId, MicroServicePO microServicePO, ClusterInfoPO clusterInfoPO) {
        // 通知集群控制台，更新当前伸缩组策略
        CreateScalingDTO createScalingDTO = new CreateScalingDTO();
        createScalingDTO.setScalingLabel(microServicePO.getId());
        EngineClusterInfo engineClusterInfo = clusterInfoPO.getClusterInfos().stream()
                .filter(info -> clusterInfoPO.getUserChooseCloud().equals(info.getProviderName()))
                .filter(info -> Objects.nonNull(info.getName())).collect(Collectors.toList()).get(0);
        createScalingDTO.setClusterNames(engineClusterInfo.getName());
        createScalingDTO.setProvider(CloudVendorsEnum.changeFromCloudTypeToDescribe(engineClusterInfo.getProviderName()));

        StrategyPO vmStrategy = strategyMapper.selectVmScaleByServiceId(svcId);
        if (Objects.nonNull(vmStrategy)) {
            ScalingPolicyDTO scalingPolicyDTO = JsonUtil.jsonStrToObject(vmStrategy.getStrategyParam(),
                    ScalingPolicyDTO.class);
            if (Objects.nonNull(scalingPolicyDTO) && !"none".equals(scalingPolicyDTO.getPolicy())) {
                createScalingDTO.setScalingPolicyPOs(scalingPolicyDTO.getParam());
            } else {
                // 删除策略
                // 对方系统支持null， 判断null则删除策略
                createScalingDTO.setScalingPolicyPOs(null);
            }
        } else {
            // 删除策略
            // 对方系统支持null， 判断null则删除策略
            createScalingDTO.setScalingPolicyPOs(null);
        }
        cloudMgmtService.insertNewScalingPolicy(Collections.singletonList(createScalingDTO));
    }

    /**
     * 更新调度策略
     *
     * @param svcId 服务id
     */
    private void updateScheduleStrategy(String svcId) {
        // 策略
        StrategyPO scheduleStrategy = strategyMapper.selectStrategyByServiceIdAndType(svcId, StrategyTypeEnum.SCHEDULE_STRATEGY.getValue());
        // 集群信息
        ClusterInfoPO clusterInfoPO = clusterInfoService.getClusterInfoBySvcId(svcId);
        // 拼接参数
        StrategyDTO strategyDTO = new StrategyDTO();
        // 隔离
        strategyDTO.setForcedIsolation(clusterInfoPO.isForcedIsolation());
        // 策略名称
        strategyDTO.setStrategyName(scheduleStrategy.getStrategyName());
        // 参数
        strategyDTO.setParams(scheduleStrategy.getStrategyParam());
        // 服务id
        strategyDTO.setServiceId(svcId);
        // 使用默认参数
        strategyDTO.setEnableDefault(scheduleStrategy.getEnableDefault());

        ScheduleService scheduleService = SpringUtil.getBean(ScheduleService.class);
        scheduleService.addScheduleStrategy(Collections.singletonList(strategyDTO));
    }

    private DeleteParam getDeleteParam(String svcId, StageVO stageVO) {
        DeleteParam deleteParam = new DeleteParam();
        deleteParam.setSvcId(svcId);

        // 顺序判断
        // 倒序的话，需要立即return，防止数据覆盖
        if (CollUtil.isNotEmpty(stageVO.getFirstStages())) {
            deleteParam.setType(StageTypeEnum.CLOUD_RESOURCE.getType());
        }
        // port
        if (CollUtil.isNotEmpty(stageVO.getSecondStages())) {
            deleteParam.setType(StageTypeEnum.SAFE_PORT.getType());
        }
        // k8s
        if (CollUtil.isNotEmpty(stageVO.getThirdStages())) {
            deleteParam.setType(StageTypeEnum.K8S.getType());
        }
        // distribute
        if (CollUtil.isNotEmpty(stageVO.getFourthStages())) {
            deleteParam.setType(StageTypeEnum.DISTRIBUTE.getType());
        }

        return deleteParam;
    }

    /**
     * 校验前3个阶段是否有错误
     *
     * @param stageVO 阶段信息
     * @return 有：true；没有：false
     */
    private boolean checkTopThreeStagesHasError(StageVO stageVO) {
        List<SingleStageVO> allStages = new ArrayList<>();
        // first
        allStages.addAll(stageVO.getFirstStages());
        // second
        allStages.addAll(stageVO.getSecondStages());
        // third
        allStages.addAll(stageVO.getThirdStages());

        boolean result = false;
        for (SingleStageVO singleStageVO : allStages) {
            if (!singleStageVO.isSuccess()) {
                result = true;
                break;
            }
        }
        return result;
    }

    private boolean checkIfSendRequestToAlgEngine(String svcId, EngineClusterInfo engineClusterInfo) {
        ClusterInfoPO clusterInfoPO = clusterInfoService.getClusterInfoBySvcId(svcId);
        AlgDeployClusterInfo userChooseClusterInfo =
                clusterInfoPO.getAlgDeployClusterInfos().stream()
                        .filter(clusterInfo -> clusterInfoPO.getUserChooseCloud().equals(clusterInfo.getProviderName()))
                        .collect(Collectors.toList()).get(0);
        // 云商切换了需要发送到集群控制台
        if (!clusterInfoPO.getUserChooseCloud().equals(engineClusterInfo.getProviderName())) {
            return false;
        }
        // 需要新建
        if (ResourceTypeEnum.CREATE.getType().equals(userChooseClusterInfo.getResourceType())) {
            return false;
        }
        // 强隔离
        if (clusterInfoPO.isForcedIsolation()) {
            return false;
        }
        return true;
    }
}
